package com.woniuxy.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.woniuxy.common.ConstantData;
import com.woniuxy.common.RedisKey;
import com.woniuxy.controller.form.AddFoodTypeForm;
import com.woniuxy.controller.form.ChangeFoodTypeStateForm;
import com.woniuxy.dao.FoodVarietyMapper;
import com.woniuxy.entity.Account;
import com.woniuxy.entity.FoodType;
import com.woniuxy.dao.FoodTypeMapper;
import com.woniuxy.entity.FoodVariety;
import com.woniuxy.exception.changeStateException.ChangeStateException;
import com.woniuxy.exception.changeStateException.ChangeStateExceptionCode;
import com.woniuxy.exception.foodTypeException.FoodTypeException;
import com.woniuxy.exception.foodTypeException.FoodTypeExceptionCode;
import com.woniuxy.service.FoodTypeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.service.dto.FoodParentTypeDto;
import com.woniuxy.service.dto.FoodTypeDto;
import com.woniuxy.service.dto.FoodTypeTreeDto;
import com.woniuxy.util.RedisUtil;
import com.woniuxy.util.WebUtil;
import org.apache.ibatis.type.TypeException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 菜品类型表 服务实现类
 * </p>
 *
 * @author zz
 * @since 2023年06月13日
 */
@Service
public class FoodTypeServiceImpl extends ServiceImpl<FoodTypeMapper, FoodType> implements FoodTypeService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private FoodTypeMapper foodTypeMapper;

    @Autowired
    private FoodVarietyMapper foodVarietyMapper;

    @Autowired
    private AccountServiceImpl accountService;


    @Autowired
    private ScheduledExecutorService threadPool;
    @Override
    @Transactional
    public FoodType addFoodType(AddFoodTypeForm addFoodTypeForm) {
        //为解决redis与数据库中数据一致性问题，采用延迟双删
        //1.删除redis中的类别信息
        redisUtil.delete(RedisKey.getFoodTypeTreeKey());

        //判断该类型是否存在
        QueryWrapper<FoodType> typeNameWrapper = new QueryWrapper<>();
        typeNameWrapper.eq("typeName",addFoodTypeForm.getTypeName());
        FoodType foodType = foodTypeMapper.selectOne(typeNameWrapper);
        if (foodType!=null){
            throw new FoodTypeException(FoodTypeExceptionCode.FOOD_TYPE_EXIST);
        }

        if (addFoodTypeForm.getParentId()!=0){
            addFoodTypeForm.setTypeSelf(1);
        }else {
            addFoodTypeForm.setTypeSelf(0);
        }

        FoodType FoodType = BeanUtil.toBean(addFoodTypeForm, FoodType.class);
        FoodType.setTypeState(ConstantData.FOOD_TYPE_STATE_NORMAL);

        if (FoodType.getParentId()==0){
            foodTypeMapper.insert(FoodType);
        }
        else {
            FoodType parentType = foodTypeMapper.selectById(addFoodTypeForm.getParentId());
            if (parentType==null){
                throw new FoodTypeException(FoodTypeExceptionCode.FOOD_TYPE_NOT_EXIST);
            }
            if (parentType.getTypeState()!=ConstantData.FOOD_TYPE_STATE_NORMAL){
                throw new FoodTypeException(FoodTypeExceptionCode.FOOD_TYPE_STATE_ERROR);
            }
            if (parentType.getTypeSelf()==ConstantData.FOOD_TYPE_NOT_NODE){
                foodTypeMapper.insert(FoodType);
            }
            else {
                QueryWrapper<FoodVariety> wrapper = new QueryWrapper<>();
                wrapper.eq("typeId",parentType.getId());
                Long count = foodVarietyMapper.selectCount(wrapper);
                if (count==0){
                    foodTypeMapper.insert(FoodType);
                    parentType.setTypeSelf(ConstantData.FOOD_TYPE_NOT_NODE);
                    foodTypeMapper.updateById(parentType);
                }
                else {
                    throw new FoodTypeException(FoodTypeExceptionCode.PARENT_TYPE_HAS_CHILD);
                }
            }

        }

        //添加一个删除redis中食品类型的线程
        threadPool.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    redisUtil.delete(RedisKey.getFoodTypeTreeKey());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        },3000, TimeUnit.MILLISECONDS);

        return FoodType;
    }

    @Override
    @Transactional
    public void changeFoodeTypeState(ChangeFoodTypeStateForm form) throws Exception {
        String accessToken = WebUtil.getRequest().getHeader("accessToken");
        Integer accountId = redisUtil.getUserIdByToken(accessToken);
        Account account = accountService.getById(accountId);
        if (!account.getRole().equals("管理员")){
            throw new FoodTypeException(8009,"无权修改");
        }
        redisUtil.delete(RedisKey.getFoodTypeTreeKey());
        FoodType FoodType = foodTypeMapper.selectById(form.getId());
        if (FoodType==null){
            throw new FoodTypeException(FoodTypeExceptionCode.FOOD_TYPE_NOT_EXIST);
        }
        if(FoodType.getTypeState().intValue() == form.getTypeState().intValue()){
            throw new ChangeStateException(ChangeStateExceptionCode.CHANGE_STATE_ALREADY);
        }
        //1.上架类别
        if (form.getTypeState()==ConstantData.FOOD_TYPE_STATE_NORMAL){
            if (FoodType.getTypeState()==ConstantData.FOOD_TYPE_STATE_DELETE){
                throw new ChangeStateException(ChangeStateExceptionCode.CHANGE_STATE_DELETE);
            }
            else {
                FoodType.setTypeState(ConstantData.FOOD_TYPE_STATE_NORMAL);
                foodTypeMapper.updateById(FoodType);

                //更改该类下面的食物状态和子类型状态
                QueryWrapper<FoodVariety> wrapper = new QueryWrapper<>();

                if (FoodType.getTypeSelf()==ConstantData.FOOD_TYPE_NODE){
                    wrapper.eq("typeId",FoodType.getId());
                    wrapper.eq("state",ConstantData.FOOD_STATE_NORMAL);
                }
                else {
                    List<Long> lists = new ArrayList<>();
                    findNodeTypeId(lists,FoodType.getId());
                    wrapper.in("typeId",lists);
                    wrapper.eq("state",ConstantData.FOOD_STATE_DISABLE);
                    //更改子类别状态
                    List<Long> allLists = new ArrayList<>();
                    findAllNodeTypeId(allLists,FoodType.getId());
                    QueryWrapper<FoodType> typeQueryWrapper = new QueryWrapper<>();
                    typeQueryWrapper.in("id",allLists);
                    typeQueryWrapper.eq("typeState",ConstantData.FOOD_TYPE_STATE_DISABLE);
                    List<FoodType> FoodTypeList = foodTypeMapper.selectList(typeQueryWrapper);
                    for (FoodType type : FoodTypeList) {
                        type.setTypeState(ConstantData.FOOD_TYPE_STATE_NORMAL);
                        foodTypeMapper.updateById(type);
                    }

                }
                List<FoodVariety> list = foodVarietyMapper.selectList(wrapper);
                for (FoodVariety foodVariety : list) {
                    foodVariety.setState(ConstantData.FOOD_STATE_NORMAL);
                    foodVarietyMapper.updateById(foodVariety);
                }

            }
        }
        //2.下架类别
        if (form.getTypeState()==ConstantData.FOOD_TYPE_STATE_DISABLE){
            if (FoodType.getTypeState()==ConstantData.FOOD_TYPE_STATE_DELETE){
                throw new ChangeStateException(ChangeStateExceptionCode.CHANGE_STATE_DELETE);
            }
            else {
                FoodType.setTypeState(ConstantData.FOOD_TYPE_STATE_DISABLE);
                foodTypeMapper.updateById(FoodType);

                //下架该类别下面的食品
                QueryWrapper<FoodVariety> wrapper = new QueryWrapper<>();
                if (FoodType.getTypeSelf()==ConstantData.FOOD_TYPE_NODE){
                    wrapper.eq("typeId",FoodType.getId());
                    wrapper.eq("state",ConstantData.FOOD_STATE_NORMAL);
                }
                else {
                    List<Long> lists = new ArrayList<>();
                    findNodeTypeId(lists,FoodType.getId());
                    wrapper.in("typeId",lists);
                    wrapper.eq("state",ConstantData.FOOD_STATE_NORMAL);
                    //更改子类别状态
                    List<Long> allLists = new ArrayList<>();
                    findAllNodeTypeId(allLists,FoodType.getId());
                    QueryWrapper<FoodType> typeQueryWrapper = new QueryWrapper<>();
                    typeQueryWrapper.in("id",allLists);
                    typeQueryWrapper.eq("typeState",ConstantData.FOOD_TYPE_STATE_NORMAL);
                    List<FoodType> FoodTypeList = foodTypeMapper.selectList(typeQueryWrapper);
                    for (FoodType type : FoodTypeList) {
                        type.setTypeState(ConstantData.FOOD_TYPE_STATE_DISABLE);
                        foodTypeMapper.updateById(type);
                    }
                }
                List<FoodVariety> list = foodVarietyMapper.selectList(wrapper);
                for (FoodVariety foodVariety : list) {
                    foodVariety.setState(ConstantData.FOOD_STATE_DISABLE);
                    foodVarietyMapper.updateById(foodVariety);
                }

            }
        }
        //3.删除类别
        if (form.getTypeState()==ConstantData.FOOD_TYPE_STATE_DELETE){

            //判断该类别下面是否有子类别或者书籍
            if (FoodType.getTypeSelf()==ConstantData.FOOD_TYPE_NODE){
                QueryWrapper<FoodVariety> wrapper = new QueryWrapper<>();
                wrapper.eq("typeId",FoodType.getId());
                List<FoodVariety> FoodVarietyList = foodVarietyMapper.selectList(wrapper);
                if (FoodVarietyList==null||FoodVarietyList.size()==0){
                    //可以删除该类别
                    FoodType.setTypeState(ConstantData.FOOD_TYPE_STATE_DELETE);
                    foodTypeMapper.updateById(FoodType);
                }
                else {
                    for (FoodVariety FoodVariety : FoodVarietyList) {
                        if (FoodVariety.getDeleted()!=ConstantData.FOOD_DELETE){
                            throw new Exception("该类别下面有书籍，不能删除");
                        }
                    }
                    //该类别下的所有书籍都已被删除，可以删除该类别
                    FoodType.setTypeState(ConstantData.FOOD_TYPE_STATE_DELETE);
                    foodTypeMapper.updateById(FoodType);
                }
            }
            else {
                List<Long> allNodeLists = new ArrayList<>();
                findAllNodeTypeId(allNodeLists,FoodType.getId());
                if (allNodeLists.size()==0){
                    //可以删除该类别
                    FoodType.setTypeState(ConstantData.FOOD_TYPE_STATE_DELETE);
                    foodTypeMapper.updateById(FoodType);
                }
                else {
                    List<Long> lists = new ArrayList<>();
                    findNodeTypeId(lists, FoodType.getId());
                    QueryWrapper<FoodVariety> wrapper = new QueryWrapper<>();
                    wrapper.in("typeId",lists);
                    List<FoodVariety> list = foodVarietyMapper.selectList(wrapper);
                    if (list.size()!=0){
                        for (FoodVariety foodVariety : list) {
                            if (foodVariety.getDeleted()!=ConstantData.FOOD_DELETE){
                                throw new ChangeStateException(ChangeStateExceptionCode.CHANGE_STATE_DELETE);
                            }
                        }
                    }
                    //可以删除该类别及其子类别
                    FoodType.setTypeState(ConstantData.FOOD_TYPE_STATE_DELETE);
                    foodTypeMapper.updateById(FoodType);
                    //删除子类别
                    QueryWrapper<FoodType> FoodTypeQueryWrapper = new QueryWrapper<>();
                    FoodTypeQueryWrapper.in("id",allNodeLists);
                    List<FoodType> FoodTypeList = foodTypeMapper.selectList(FoodTypeQueryWrapper);
                    for (FoodType type : FoodTypeList) {
                        type.setTypeState(ConstantData.FOOD_TYPE_STATE_DELETE);
                        foodTypeMapper.updateById(type);
                    }

                }
            }

        }


    }

    @Override
    public List<FoodTypeDto> showFoodNodeType() {
        QueryWrapper<FoodType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("typeSelf",1);
        queryWrapper.eq("typeState",ConstantData.FOOD_TYPE_STATE_NORMAL);
        List<FoodType> list = list(queryWrapper);
        List<FoodTypeDto> foodTypeDtos = BeanUtil.copyToList(list, FoodTypeDto.class);
        return foodTypeDtos;
    }

    @Override
    public List<FoodTypeTreeDto> showFoodTypeTree() {
        //如果redis中存有类别信息，就直接取
        if (redisUtil.exist(RedisKey.getFoodTypeTreeKey())){
            String str = redisUtil.getString((RedisKey.getFoodTypeTreeKey()));
            return JSONUtil.toList(str, FoodTypeTreeDto.class);
        }else {
            QueryWrapper<FoodType> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("parentId",0);
            List<FoodType> foodTypes = foodTypeMapper.selectList(queryWrapper);
            List<FoodTypeTreeDto> types = new ArrayList<>();
            for (FoodType foodType : foodTypes) {
                FoodTypeTreeDto typeTreeDto = BeanUtil.toBean(foodType, FoodTypeTreeDto.class);
                findChildTypeTree(typeTreeDto);
                typeTreeDto.setTypeState(foodType.getTypeState()==1?"可用":foodType.getTypeState()==0?"删除":"禁用");
                types.add(typeTreeDto);
            }
            //将类别信息存入redis中
            String jsonStr = JSONUtil.toJsonStr(types);
            redisUtil.setString(RedisKey.getFoodTypeTreeKey(),jsonStr);
            return types;
        }
    }

    @Override
    public List<FoodParentTypeDto> showParentTypeTree() {
        QueryWrapper<FoodType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parentId",0).ne("typeState",0);
        List<FoodType> foodTypes = foodTypeMapper.selectList(queryWrapper);
        List<FoodParentTypeDto> lists = BeanUtil.copyToList(foodTypes, FoodParentTypeDto.class);
        return lists;
    }


    public void findChildTypeTree(FoodTypeTreeDto foodTypeTreeDto){
        QueryWrapper<FoodType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parentId",foodTypeTreeDto.getId()).ne("typeState",0);
        List<FoodType> foodTypes = foodTypeMapper.selectList(queryWrapper);
        for (FoodType foodType : foodTypes) {
            FoodTypeTreeDto treeDto = BeanUtil.toBean(foodType, FoodTypeTreeDto.class);
            treeDto.setTypeState(foodType.getTypeState()==1?"可用":foodType.getTypeState()==0?"删除":"禁用");
            foodTypeTreeDto.getList().add(treeDto);
            findChildTypeTree(treeDto);
        }
    }


    public void findNodeTypeId(List<Long> NodeList, Long typeId) throws Exception{
        QueryWrapper<FoodType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parentId", typeId).ne("typeState",0);
        List<FoodType> list = foodTypeMapper.selectList(queryWrapper);
        for (FoodType foodType : list) {
            if (foodType.getTypeSelf()==ConstantData.FOOD_TYPE_NODE){
                NodeList.add(foodType.getId());
            }
            else {
                findNodeTypeId(NodeList,foodType.getId());
            }
        }
    }

    public void findAllNodeTypeId(List<Long> NodeList, Long typeId) throws Exception{
        QueryWrapper<FoodType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parentId", typeId).ne("typeState",0);
        List<FoodType> list = foodTypeMapper.selectList(queryWrapper);
        for (FoodType foodType : list) {
            NodeList.add(foodType.getId());
            if (foodType.getTypeSelf()==ConstantData.FOOD_TYPE_NOT_NODE){
                findNodeTypeId(NodeList,foodType.getId());
            }
        }

    }
}
